#include <stdio.h>
#include <sched.h>
#include <unistd.h>
#include <stdlib.h>
#include <errno.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <assert.h>
#include <fcntl.h>
#include <sys/stat.h> 
#include <string.h>
#include <sys/times.h>
#include <sys/file.h>

#include "hw2_syscalls.h"



int fibonaci(int n)
{
    if (n < 2)
	printf("FINISH! pid : %d \n" ,getpid());
        return n;
    return fibonaci(n-1) + fibonaci(n-2);
}

void run_fib(int num_trials, int n)
{
	struct sched_param sp;
	sp.sched_priority = 0;
	sp.trial_num = num_trials;
	int i = sched_setscheduler(getpid(), 4,  ((struct sched_param *) (&sp)));
	if (i == -1){
		return;
	}
	printf("pid : %d ", getpid());
	printf("trials :  %d ", sp.trial_num);
	printf ("return status : %d \n", i);
	printf("ERRNO : %s \n", strerror(errno));
	printf("is_MQ : %d \n", is_mq(getpid()));

	fibonaci(n);
}

const char * reason_to_str(enum sched_reason reason)
{
	switch (reason) {
	case SWITCH_REASON_CREATE:
		return "SWITCH_REASON_CREATE";
	case SWITCH_REASON_END:
		return "SWITCH_REASON_END";
	case SWITCH_REASON_YIELD:
		return "SWITCH_REASON_YIELD";
	case SWITCH_REASON_MQ_OVERDUE:
		return "SWITCH_REASON_MQ_OVERDUE";
	case SWITCH_REASON_TO_WAIT:
		return "SWITCH_REASON_TO_WAIT";
	case SWITCH_REASON_FROM_WAIT:
		return "SWITCH_REASON_FROM_WAIT";
	case SWITCH_REASON_TIMESLICE_END:
		return "SWITCH_REASON_TIMESLICE_END";
	case SWITCH_REASON_INVALID:
		return "SWITCH_REASON_INVALID";
	default:
		return "SWITCH_REASON_???";
	}
}

const char* policy_to_str(int policy)
{
    switch (policy) {
    case 0:
        return "OTHER";
    case 1:
        return "FIFO";
    case 2:
        return "RR";
    case 4:
        return "MQ";
    }
    
    return "????";
}


/*void print_statistics()
{
	struct switch_info info[150];
	int i, res;

	res = get_scheduling_statistic(info);
	if(res == 0 ) {
	    exit(0);
	}
	printf("\nPREV_PID  |NEXT_PID  |PREV_POLICY |NEXT_POLICY |TIME      |REASON    \n");
	for(i = 0 ; i < res; i++){
	    printf("%10d|%10d|%12d|%12d|%10lu|%10d\n",
	     info[i].previous_pid, info[i].next_pid, info[i].previous_policy,
	     info[i].next_policy, info[i].time, info[i].reason);
	}

}
*/

void print_stats()
{
	struct switch_info info[150];
	int i, ret;

	if (-1 == (ret = get_scheduling_statistic(info))) {
		perror("Can't get stats");
		exit(1);
	}
    printf("[U] printing %d stats:\n", ret);
	for (i = 0; i < ret; ++i) {
		printf("%10lu: [%5d|%11s]->[%5d|%11s] = %s\n",
		       info[i].time,
		       info[i].previous_pid,
		       policy_to_str(info[i].previous_policy),
		       info[i].next_pid,
		       policy_to_str(info[i].next_policy),
		       reason_to_str(info[i].reason));
	}
}



int main(int argc, char** argv){
    if((argc -1) %2 != 0 || argc-1 == 0 ){
	    printf("argc /2 : %d",( argc- 1) %2 );
	    printf("argc %d", argc);
        printf("USAGE : sched_tester <number_of_trials1> <n1> <number_of_trials2> <n2> \n");
        return 0;
    }

    // go over the input.
   int i; 


    for(i =1 ; i < argc /2 +1 ; i++){
        int number_of_trials = atoi(argv[i]);
        int n = atoi(argv[i+1]);

	 printf( " n = %d  and argv[%d] = %s" , n, i+1, argv[i+1]);
	 printf(" number of trials i= %d and argv[%d] = %s\n", number_of_trials, i, argv[i]);

        int res = fork();
        if(!res){
	
            run_fib(number_of_trials, n);
	    printf("FINISH run_fib\n");
            exit(0);
        }
    }

	while (wait(NULL) != -1) {
	}

	print_stats();
    return 0;
}
